#include "Poller.h"
#include "Channel.h"
#include "Logger.h"
#include <assert.h>
#include <utility>
#include <cerrno>
#include <stdlib.h>

Poller::Poller()
{
    _epfd = epoll_create(MAX_EPOLLEVENTS);
    if (_epfd == -1)
    {
        ERR_LOG("epoll 句柄创建失败");
        abort();
    }
}

//------------------   私有成员方法   ----------------

// 1. 更新Channel，就是调用epoll_ctl add/mod/del
void Poller::Updata(Channel *channel, int op)
{
    int fd = channel->Fd();
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = channel->Events();
    int ret = epoll_ctl(_epfd, op, fd, &ev);
    if (ret < 0)
    {
        ERR_LOG("EPOLL_CTL FAILED");
    }
    return;
}

// 2. 判断一个Channel是否已经添加了事件监控
bool Poller::HasChannel(Channel *channel)
{
    auto pos = _channels.find(channel->Fd());
    if (pos == _channels.end())
    {
        return false;
    }
    return true;
}

// ----------------  公有成员方法   ------------------

// 1. 添加修改事件监控
void Poller::UpdataEvent(Channel *channel)
{
    // 1). 先判断当前channel是否已经已经有事件监控了
    bool ret = HasChannel(channel);
    if (ret == false) // 没有，就添加事件监控
    {
        _channels.insert(std::make_pair(channel->Fd(), channel));
        return Updata(channel, EPOLL_CTL_ADD);
    }
    return Updata(channel, EPOLL_CTL_MOD);
}

// 2. 移除事件监控
void Poller::RemoveEvent(Channel *channel)
{
    bool ret = HasChannel(channel);
    if (ret == false)
        return;
    _channels.erase(channel->Fd());
    return Updata(channel, EPOLL_CTL_DEL); //  写错EPOLL_CTL_MOD这个了
}

// 3. 开始监控，返回活跃连接
void Poller::Poll(std::vector<Channel *> *active)
{
    // <0 阻塞等待
    int n = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);
    if (n < 0) // 没有就绪事件
    {
        if (errno == EINTR) // 被信号打断
            return;
        // 等待失败 doing
        abort();
    }
    // 等待成功
    for (int i = 0; i < n; i++)
    {
        auto it = _channels.find(_evs[i].data.fd);
        assert(it != _channels.end());
        it->second->SetREvents(_evs[i].events); // 设置实际就绪的事件
        active->push_back(it->second);
    }
}
